package edu.kit.csl.cratylus.datatypes;

/**
 * Instances of this class represent words in the source or target language.
 * Words in the source language are stored with their written representation.
 * Words in the target language correspond to phoneme sequences.
 */
public class Word {

	private String content;
	private boolean fixed;
	private Word relatedWord;
	private boolean containsNoise;
	
	/**
	 * Constructor with isFixed semantics. Initializes the related word with
	 * {@code null}.
	 * 
	 * @param content string representation of the word
	 * @param fixed flag if this word is fixed or not. Semantics differ
	 * 			between source and target language.
	 * @throws NullPointerException if <code>content</code> is null
	 */
	public Word(String content, boolean fixed) 
			throws NullPointerException {
		if (content == null) {
			throw new NullPointerException();
		}
		this.content = content;
		this.fixed = fixed;
		this.relatedWord = null;
		containsNoise = false;
	}
	
	/**
	 * Simple constructor. Sets the isFixed flag to false and initializes the 
	 * related word with {@code null}.
	 * 
	 * @param content string representation of the word
	 * @throws NullPointerException if <code>content</code> is null
	 */
	public Word(String content) throws NullPointerException {
		if (content == null) {
			throw new NullPointerException();
		}
		this.content = content;
		this.fixed = false;
		this.relatedWord = null;
		containsNoise = false;
	}

	/**
	 * Get the related word. If the word is a target word, this should point
	 * to the associated source word. Can be {@code null}.
	 * 
	 * @return the related word
	 */
	public Word getRelatedWord() {
		return relatedWord;
	}
	
	/**
	 * Checks if this word is empty, i.e. has the length zero. Empty words may
	 * be produced by non-trivial {@link CorpusUpdater}.
	 * 
	 * @return true if the content of this word is empty, false otherwise
	 */
	public boolean isEmpty() {
		return content.isEmpty();
	}

	/**
	 * Set the related word. If the word is a target word, this should point
	 * to the associated source word. Otherwise, set to {@code null}.
	 * 
	 * @param relatedWord the new related word
	 */
	public void setRelatedWord(Word relatedWord) {
		this.relatedWord = relatedWord;
	}

	/**
	 * Get the string representation of the word.
	 * 
	 * @return the string representation of the word
	 */
	public String getContent() {
		return content;
	}
	
	/**
	 * Set the string representation of the word.
	 * 
	 * @param the new string representation (must not be null)
	 * @throws NullPointerException if {@code content} is {@code null}.
	 */
	public void setContent(String content) throws NullPointerException {
		if (content == null) {
			throw new NullPointerException();
		}
		this.content = content;
	}

	/**
	 * Get the content of the <code>fixed</code> flag.
	 * 
	 * @return <code>true</code> if the word is fixed, <code>false</code>
	 * 		otherwise
	 */
	public boolean isFixed() {
		return fixed;
	}
	
	/**
	 * Set the <code>fixed</code>
	 * 
	 * @param fixed new value of the fixed flag
	 */
	public void setFixed(boolean fixed) {
		this.fixed = fixed;
	}
	
	/**
	 * Set the <code>noise</code>
	 * 
	 * @param noise new value of the noise flag
	 */
	public void setNoise(boolean noise) {
		containsNoise = noise;
	}
	
	/**
	 * Contains this word noise? This is usually determined by the splitter.
	 * 
	 * @return <code>true</code> if the word contains noise, {@code false}
	 * 		otherwise
	 */
	public boolean isNoise() {
		return containsNoise;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return 31 + content.hashCode();
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null || !(obj instanceof Word)) {
			return false;
		}
		return content.equals(((Word) obj).content);
	}
}
